// File: bresenham.c
//Purpose:  bresenham line draw downcoded to C

// our code starts here

#include "DowncodedBresenham.h"

static jclass biclass = NULL;
static jmethodID bimid;


// macro to call pixel set on bufferedimage
#define SETRGB(bi,x,y,rgbval) env->CallVoidMethod(bi,bimid,x,y,rgbval)

static void octant0(JNIEnv *env,jobject bi, jint x0, jint y0, int dx, int dy,
		int xdirection);
static void octant1(JNIEnv *env,jobject bi, jint x0, jint y0, int dx, int dy,
		int xdirection);		


JNIEXPORT void JNICALL Java_DowncodedBresenham_drawLine
		(JNIEnv *env, jobject thisObj, jobject bufferedImage, 
		 jint x0, jint y0, jint x1, jint y1){
	int temp,dx,dy;
	
	
	// set up class and method pointers
	if (biclass == NULL){
		biclass = env->GetObjectClass(bufferedImage);
		bimid = env->GetMethodID(biclass,"setRGB","(III)V");		
	}		
	// reduce to half the octant cases by always drawing + in y
	if (y0>y1) {
		temp = y0;
		y0 = y1;
		y1 = temp;
		temp = x0;
		x0 = x1;
		x1 = temp;
	} 	
	dx = x1-x0;
	dy = y1-y0;
	if (dx>0) {
		if (dx>dy) {
			octant0(env,bufferedImage,x0,y0,dx,dy,1);
		} else {
			octant1(env,bufferedImage,x0,y0,dx,dy,1);
		}
	} else {
		dx = -dx;
		if (dx>dy) {
			octant0(env,bufferedImage,x0,y0,dx,dy,-1);
		} else {
			octant1(env,bufferedImage,x0,y0,dx,dy,-1);
		}	
	}				
}	

static void octant0(JNIEnv *env,jobject bi, jint x0, jint y0, int dx, int dy,
		int xdirection){
		
	int DeltaYx2;
	int DeltaYx2MinusDeltaXx2;
	int ErrorTerm;
	jint pix = 0xffffffff;
		
	// set up initial error term and drawing values
	DeltaYx2 = dy*2;
	DeltaYx2MinusDeltaXx2 = DeltaYx2 - (dx*2);
	ErrorTerm = DeltaYx2 - dx;
		
	// draw loop
	//bi.setRGB(x0,y0,pix); // draws a single point
	SETRGB(bi,x0,y0,pix);
	while ( dx-- > 0){
		// check if we need to advance y
		if (ErrorTerm >=0){
			// advance Y and reset ErrorTerm
			y0++;
			ErrorTerm += DeltaYx2MinusDeltaXx2;	
		} else {
			// add error to ErrorTerm
			ErrorTerm += DeltaYx2;
		}		
		x0 += xdirection;	
		//bi.setRGB(x0,y0,pix);
		SETRGB(bi,x0,y0,pix);
	}			
}	

static void octant1(JNIEnv *env,jobject bi, jint x0, jint y0, int dx, int dy,
		int xdirection){
		
	int DeltaXx2;
	int DeltaXx2MinusDeltaYx2;
	int ErrorTerm;
	jint pix = 0xffffffff;
		
	// set up initial error term and drawing values
	DeltaXx2 = dx * 2;
	DeltaXx2MinusDeltaYx2 = DeltaXx2 - (dy*2);
	ErrorTerm = DeltaXx2- dy;
		
	// draw loop
	//bi.setRGB(x0,y0,pix);
	SETRGB(bi,x0,y0,pix);
	while ( dy-- > 0) {
		// check if we need to advance x
		if (ErrorTerm >= 0) {
			// advance X and reset ErrorTerm
			x0 += xdirection;
			ErrorTerm += DeltaXx2MinusDeltaYx2;
		} else {
			// add to ErrorTerm
			ErrorTerm += DeltaXx2;
		}
		y0++;
		//bi.setRGB(x0,y0,pix);
		SETRGB(bi,x0,y0,pix);
	}	
}
	

